/*
 *  Copyright (c) 2023-2025 苏州棱镜七彩信息科技有限公司 (Suzhou PrismAurora Information Technology Co.,Ltd)
 *  sbom-generate is licensed under Mulan PSL v2.
 *  You can use this software according to the terms and conditions of the Mulan PSL v2.
 *  You may obtain a copy of Mulan PSL v2 at:
 *           http://license.coscl.org.cn/MulanPSL2
 *  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *  See the Mulan PSL v2 for more details.
 * */
package com.ljqc.impl.sbom;

import com.ljqc.abs.sbom.SBomGenerate;
import com.ljqc.entity.DocMetaInfo;
import com.ljqc.entity.PackageInfo;
import com.ljqc.entity.SPDXDocument;
import com.ljqc.entity.SPDXPackage;
import com.ljqc.entity.SPDXRelationship;
import com.ljqc.utils.FileUtils;

import java.io.File;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * @ClassName SPDXTagValueGenerate
 * @Description
 * @Date 2025/3/14 13:46
 * @Version V1.0
 **/
public class SPDXGenerate implements SBomGenerate<SPDXDocument, PackageInfo> {

    private static final Logger LOGGER = Logger.getLogger(SPDXGenerate.class.getName());
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");

    @Override
    public SPDXDocument generateByInfoList(List<PackageInfo> infoList, DocMetaInfo docMetaInfo) {
        LOGGER.log(Level.INFO, "开始生成SPDX文档，包信息数量：{0}", infoList.size());

        String uuid = UUID.randomUUID().toString();
        String documentName = docMetaInfo.getDocName();
        String docName = documentName != null && !documentName.trim().isEmpty()
                ? documentName
                : "SBOM-" + uuid;
        String created = LocalDateTime.now(ZoneOffset.UTC).format(DATE_TIME_FORMATTER);
        LOGGER.log(Level.FINE, "文档基本信息：名称={0}，UUID={1}，创建时间={2}",
                new Object[]{docName, uuid, created});

        LOGGER.log(Level.FINE, "开始转换包信息为SPDX格式");
        List<SPDXPackage> spdxPackages = infoList.stream()
                .map(pkg -> {
                    String pkgUuid = UUID.randomUUID().toString().substring(0, 8); /*截取8位做为标识符*/
                    String filePath = pkg.getFileName();
                    String fileMd5 = FileUtils.calculateMD5(new File(filePath)).substring(0, 8); /*截取8位做为标识符*/
                    String componentType = pkg.getType() != null ? pkg.getType() : "unknown";
                    String spdxId = String.format("SPDXRef-PACKAGE-%s-%s-%s-%s-%s",
                            pkgUuid,
                            fileMd5,
                            componentType,
                            pkg.getName(),
                            pkg.getVersion());

                    LOGGER.log(Level.FINE, "处理包：{0}:{1}，SPDX ID：{2}",
                            new Object[]{pkg.getName(), pkg.getVersion(), spdxId});

                    return SPDXPackage.builder()
                            .name(pkg.getName())
                            .id(spdxId)
                            .version(pkg.getVersion())
                            .fileName(pkg.getFileName())
                            .downloadLocation(pkg.getDownloadUrl() == null ? "NOASSERTION" : pkg.getDownloadUrl())
                            .checksum(pkg.getChecksum() == null ? "NOASSERTION" : pkg.getChecksum())
                            .homePage("NOASSERTION")
                            .sourceInfo(String.format("Package %s version %s", pkg.getName(), pkg.getVersion()))
                            .licenseConcluded(pkg.getLicense() != null ? pkg.getLicense() : "NOASSERTION")
                            .licenseDeclared(pkg.getLicense() != null ? pkg.getLicense() : "NOASSERTION")
                            .summary("Package " + pkg.getName())
                            .description("Generated by SBOM Generator")
                            .externalRef(String.format("%s/%s@%s",
                                    componentType,
                                    pkg.getName().replace(":", "/"),
                                    pkg.getVersion()))
                            .releaseDate("NOASSERTION")
                            .build();
                })
                .collect(Collectors.toList());
        LOGGER.log(Level.FINE, "SPDX包信息转换完成，共 {0} 个包", spdxPackages.size());

        LOGGER.log(Level.FINE, "开始构建包之间的关系");
        List<SPDXRelationship> relationships = new ArrayList<>();
        infoList.stream()
                .filter(pkg -> pkg.getParentName() != null && !pkg.getParentName().isEmpty())
                .forEach(pkg -> {
                    LOGGER.log(Level.FINE, "处理包 {0}:{1} 的依赖关系",
                            new Object[]{pkg.getName(), pkg.getVersion()});
                    String childId = spdxPackages.stream()
                            .filter(spdxPkg ->
                                    spdxPkg.getName().equals(pkg.getName())
                                            && spdxPkg.getVersion().equals(pkg.getVersion()))
                            .findFirst()
                            .map(SPDXPackage::getId)
                            .orElse(null);

                    String parentId = spdxPackages.stream()
                            .filter(spdxPkg ->
                                    spdxPkg.getName().equals(pkg.getParentName())
                                            && spdxPkg.getVersion().equals(pkg.getParentVersion()))
                            .findFirst()
                            .map(SPDXPackage::getId)
                            .orElse(null);

                    if (childId != null && parentId != null) {
                        LOGGER.log(Level.FINE, "添加依赖关系：{0} -> {1}", new Object[]{childId, parentId});
                        relationships.add(SPDXRelationship.builder()
                                .id(childId)
                                .parentId(parentId)
                                .build());
                    } else {
                        LOGGER.log(Level.FINE, "无法建立依赖关系");
                    }
                });
        LOGGER.log(Level.FINE, "关系构建完成，共 {0} 个关系", relationships.size());

        SPDXDocument document = SPDXDocument.builder()
                .documentName(docName)
                .user(docMetaInfo.getUser() == null ? "NONE" : docMetaInfo.getUser())
                .userGroup(docMetaInfo.getUserGroup() == null ? "NONE" : docMetaInfo.getUserGroup())
                .documentNamespace(uuid)
                .created(created)
                .packages(spdxPackages)
                .relationships(relationships)
                .build();
        LOGGER.log(Level.INFO, "SPDX文档生成完成，文档名称：{0}", docName);
        return document;
    }

}
